package com.nowcoder.community.controller;

import com.alibaba.fastjson.JSONObject;
import com.nowcoder.community.entity.Event;
import com.nowcoder.community.entity.Message;
import com.nowcoder.community.entity.Page;
import com.nowcoder.community.entity.User;
import com.nowcoder.community.service.MessageService;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.util.CommunityConstant;
import com.nowcoder.community.util.GenerateUtil;
import com.nowcoder.community.util.HostHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.HtmlUtils;

import java.util.*;

/**
 * @BelongsProject: community
 * @BelongsPackage: com.nowcoder.community.controller.interceptor
 * @Author: Master_XXJS
 * @CreateTime: 2023-01-02  14:11
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Controller
public class MessageController implements CommunityConstant {

    @Autowired
    private MessageService messageService;
    @Autowired
    private HostHolder hostHolder;
    @Autowired
    private UserService userService;

    /**
     * 私信列表
     * @param model 返回前端的数据封装器
     * @param page 分页实体对象
     * @return
     */
    @RequestMapping(path = "/letter/list", method = RequestMethod.GET)
    public String getLetterList(Model model, Page page){
        log.error("私信列表");
        //page 分页信息
        page.setPath("/letter/list");
        page.setLimit(5);
        //总的显示数据有多少条
        page.setRows(messageService.findConversationCount(hostHolder.getUser().getId()));

        //查询私信列表集合
        List<Message> messageList = messageService.findConversations(hostHolder.getUser().getId(),page.getOffset(),page.getLimit());
        //将每一个私信会话里面的详细内容补充完整,只需要补充当前 页面 需要看见的数据就行了，每一个会话里面的详细的聊天记录不需要封装，不然浪费资源
        //再定义一个用来 存储 详细 列表的 list 集合
        List<Map<String,Object>> messages = new ArrayList<>();
        //对前面查询出来的私信列表做出详细的处理
        if (messages != null){
            for (Message message : messageList){
                Map<String,Object> map = new HashMap<>();
                int letterCount = messageService.findLetterCount(message.getConversationId());
                int letterUnreadCount = messageService.findLetterUnreadCount(hostHolder.getUser().getId(), message.getConversationId());
                //将当前的会话，现在通过遍历，是单个独立体，封装到 map 集合中去
                map.put("conversation",message);
                map.put("letterCount",letterCount);
                map.put("unreadCount",letterUnreadCount);
                int targetId = hostHolder.getUser().getId() == message.getFromId() ? message.getToId() : message.getFromId();
                map.put("target", userService.findUserById(targetId));

                //将 详细的会话， 装填到 私信list 集合中去
                messages.add(map);
            }
        }
        model.addAttribute("conversations", messages);

        // 查询未读消息数量,也就是 总的未读的会话有几个，而不是 会话中未读的信息数量
        int letterUnreadCount = messageService.findLetterUnreadCount(hostHolder.getUser().getId(), null);
        model.addAttribute("letterUnreadCount", letterUnreadCount);

        return "/site/letter";
    }

    /**
     * 会话详情页
     * @param conversationId 会话id，页面点击哪一个会话，就获取哪一个会话的id
     * @param page 分页
     * @param model 返回前端的数据封装器
     * @return
     */
    @RequestMapping(path = "/letter/detail/{conversationId}", method = RequestMethod.GET)
    public String getLetterDetail(@PathVariable("conversationId") String conversationId, Page page, Model model) {
        // 分页信息
        page.setLimit(5);
        page.setPath("/letter/detail/" + conversationId);
        page.setRows(messageService.findLetterCount(conversationId));

        // 私信列表
        List<Message> letterList = messageService.findLetters(conversationId, page.getOffset(), page.getLimit());
        List<Map<String, Object>> letters = new ArrayList<>();
        if (letterList != null) {
            for (Message message : letterList) {
                Map<String, Object> map = new HashMap<>();
                map.put("letter", message);
                //显示每一条信息，是谁发的，两个人都发，区分一下
                map.put("fromUser", userService.findUserById(message.getFromId()));
                letters.add(map);
            }
        }
        model.addAttribute("letters", letters);

        // 私信目标，也就是显示对方是谁，来自 xxx 的私信
        model.addAttribute("target", getLetterTarget(conversationId));

        /*
            个人觉得，应该和 qq 一样，只要你打开了 会话（进去了），里面的消息一下子全部变成 已读
            而不用单独的去寻找哪一条消息是 上次未读的
            因为这里是 分页处理的，所以，可能下一页没有点击打开，没看到下一页，所以下一页的消息也是未读状态
            qq 的消息不是分页显示的，所以一下子全部改为 已读状态 没问题
         */
        // 设置已读
        //得到的是，会话中未读消息 id 集合
        List<Integer> ids = getLetterIds(letterList);
        if (!ids.isEmpty()) {
            //将 这些 id 改为已读的
            messageService.readMessage(ids);
        }

        return "/site/letter-detail";
    }

    /**
     * 获取 会话（点开） 中，上面来自 xxx 私信的 用户，判断谁是 发私信的人
     * 因为，conversation_id 是两个人的 id 一起拼接的
     * @param conversationId
     * @return
     */
    private User getLetterTarget(String conversationId) {
        String[] ids = conversationId.split("_");
        int id0 = Integer.parseInt(ids[0]);
        int id1 = Integer.parseInt(ids[1]);

        //用当前的 登录用户的 id 进行排除
        if (hostHolder.getUser().getId() == id0) {
            return userService.findUserById(id1);
        } else {
            return userService.findUserById(id0);
        }
    }

    /**
     * 记录 两个人的会话中 未读消息的 id 集合
     * @param letterList
     * @return
     */
    private List<Integer> getLetterIds(List<Message> letterList) {
        List<Integer> ids = new ArrayList<>();

        if (letterList != null) {
            for (Message message : letterList) {
                //如果当前用户的 id 就是消息的 目标 id 并且 状态为0（未读）的话，这个消息的 id 进行记录
                if (hostHolder.getUser().getId() == message.getToId() && message.getStatus() == 0) {
                    ids.add(message.getId());
                }
            }
        }

        return ids;
    }

    /**
     * 进行 会话 中发送私信
     * @param toName 发送的目标的名字
     * @param content 发送的内容
     * @return
     */
    @RequestMapping(path = "/letter/send", method = RequestMethod.POST)
    @ResponseBody
    public String sendLetter(String toName, String content) {
        //查找发送的目标人，是否存在（是否注册的用户中，存在这个 名字 的用户）
        User target = userService.findUserByName(toName);
        if (target == null) {
            return GenerateUtil.getJsonString(1, "目标用户不存在!");
        }

        Message message = new Message();
        message.setFromId(hostHolder.getUser().getId());
        message.setToId(target.getId());
        //设置 当前的会话的 id，根据两个用户的id进行拼接的，小的在前面
        if (message.getFromId() < message.getToId()) {
            message.setConversationId(message.getFromId() + "_" + message.getToId());
        } else {
            message.setConversationId(message.getToId() + "_" + message.getFromId());
        }
        message.setContent(content);
        message.setCreateTime(new Date());
        messageService.addMessage(message);

        return GenerateUtil.getJsonString(0);
    }

    /**
     * 系统通知的列表的数据
     * @param model
     * @return
     */
    @RequestMapping(path = "/notice/list", method = RequestMethod.GET)
    public String getNoticeList(Model model) {
        User user = hostHolder.getUser();

        // 查询评论类通知,评论帖子或者回复
        Message message = messageService.findLatestNotice(user.getId(), TOPIC_COMMENT);
        if (message != null) {
            Map<String, Object> messageVO = new HashMap<>();
            messageVO.put("message", message);

            System.err.println(message.getContent());
            //进行将 html 转义字符（存入数据库的时候转换为json自动转义了） 还原
            String content = HtmlUtils.htmlUnescape(message.getContent());
            System.err.println("转义之后："+message.getContent());
            Map<String, Object> data = JSONObject.parseObject(content, HashMap.class);

            messageVO.put("user", userService.findUserById((Integer) data.get("userId")));
            messageVO.put("entityType", data.get("entityType"));
            messageVO.put("entityId", data.get("entityId"));
            messageVO.put("postId", data.get("postId"));

            int count = messageService.findNoticeCount(user.getId(), TOPIC_COMMENT);
            messageVO.put("count", count);

            int unread = messageService.findNoticeUnreadCount(user.getId(), TOPIC_COMMENT);
            messageVO.put("unread", unread);

            model.addAttribute("commentNotice", messageVO);
        }


        // 查询点赞类通知
        message = messageService.findLatestNotice(user.getId(), TOPIC_LIKE);
        if (message != null) {
            Map<String, Object> messageVO = new HashMap<>();
            messageVO.put("message", message);

            String content = HtmlUtils.htmlUnescape(message.getContent());
            Map<String, Object> data = JSONObject.parseObject(content, HashMap.class);

            messageVO.put("user", userService.findUserById((Integer) data.get("userId")));
            messageVO.put("entityType", data.get("entityType"));
            messageVO.put("entityId", data.get("entityId"));
            messageVO.put("postId", data.get("postId"));

            int count = messageService.findNoticeCount(user.getId(), TOPIC_LIKE);
            messageVO.put("count", count);

            int unread = messageService.findNoticeUnreadCount(user.getId(), TOPIC_LIKE);
            messageVO.put("unread", unread);
            model.addAttribute("likeNotice", messageVO);
        }

        // 查询关注类通知
        message = messageService.findLatestNotice(user.getId(), TOPIC_FOLLOW);
        if (message != null) {
            Map<String, Object> messageVO = new HashMap<>();
            messageVO.put("message", message);

            String content = HtmlUtils.htmlUnescape(message.getContent());
            Map<String, Object> data = JSONObject.parseObject(content, HashMap.class);

            messageVO.put("user", userService.findUserById((Integer) data.get("userId")));
            messageVO.put("entityType", data.get("entityType"));
            messageVO.put("entityId", data.get("entityId"));

            int count = messageService.findNoticeCount(user.getId(), TOPIC_FOLLOW);
            messageVO.put("count", count);

            int unread = messageService.findNoticeUnreadCount(user.getId(), TOPIC_FOLLOW);
            messageVO.put("unread", unread);
            model.addAttribute("followNotice", messageVO);
        }

        // 查询未读消息数量
        int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(), null);
        model.addAttribute("letterUnreadCount", letterUnreadCount);
        int noticeUnreadCount = messageService.findNoticeUnreadCount(user.getId(), null);
        model.addAttribute("noticeUnreadCount", noticeUnreadCount);

        return "/site/notice";
    }

    //打开通知会话，里面详细的通知信息
    @RequestMapping(path = "/notice/detail/{topic}", method = RequestMethod.GET)
    public String getNoticeDetail(@PathVariable("topic") String topic,Page page,Model model) {
        //设置分页
        page.setLimit(5);
        page.setPath("/notice/detail/" + topic);
        page.setRows(messageService.findNoticeCount(hostHolder.getUser().getId(), topic));

        //查询 通知列表数据
        List<Message> notices = messageService.findNotices(hostHolder.getUser().getId(), topic, page.getOffset(), page.getLimit());
        //将 通知列表数据进行 vo转换
        //因为 message 表中的content存放 事件对象Event的时候，存放的是 JSON 数据
        //notices 实体的信息太少了
        List<Map<String, Object>> noticeVoLists = new ArrayList<>();
        if (notices != null) {
            for (Message message : notices) {
                Map<String, Object> map = new HashMap<>();
                //将 message 中存放的 content 的JSON数据 转换为 event 事件对象
                String content = HtmlUtils.htmlUnescape(message.getContent());
                //这里转换的不是 event 对象，而是 HashMap 对象，也可以，因为都一样
                Map<String, Object> data = JSONObject.parseObject(content, HashMap.class);
                //通知
                map.put("notice", message);
                map.put("user", userService.findUserById((Integer) data.get("userId")));
                map.put("entityType", data.get("entityType"));
                map.put("entityId", data.get("entityId"));
                map.put("postId", data.get("postId"));
                //通知作者
                map.put("fromUser", userService.findUserById(message.getFromId()));

                noticeVoLists.add(map);
            }
            model.addAttribute("notices", noticeVoLists);
        }

        //设置已读
        List<Integer> letterIds = getLetterIds(notices);
        if (!letterIds.isEmpty()) {
            messageService.readMessage(letterIds);
        }

        return "/site/notice-detail";
    }
}

